# -*- coding: UTF-8 -*-
"""
Ce module permet de formater les dates de la même manière que la fonction PHP date()
Voir http://www.php.net/date pour plus de détails sur les chaînes de formatage

Usage :
>>> import datetime
>>> d = datetime.datetime.now()
>>> df = DateFormat(d)
>>> print df.format('j F Y H:i')
7 October 2003 11:39
>>>
"""

from calendar import isleap
from dates import MONTHS, MONTHS_AP, MONTHS_ENGLISH, WEEKDAYS

class DateFormat:
    year_days = [None, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334]

    def __init__(self, d):
        self.date = d

    def a(self):
        "'a.m.' ou 'p.m.'"
        if self.date.hour > 11:
            return 'p.m.'
        return 'a.m.'

    def A(self):
        "'AM' ou 'PM'"
        if self.date.hour > 11:
            return 'PM'
        return 'AM'

    def B(self):
        "Heure Internet Swatch"
        raise NotImplementedError

    def c(self):
        "Mois, en trois lettres, en anglais; par ex : 'jan'"
        return MONTHS_ENGLISH[self.date.month][0:3]

    def d(self):
        "Jour du mois, sur deux chiffres (avec un zéro initial); de '01' à '31'"
        return '%02d' % self.date.day

    def D(self):
        "Jour de la semaine, en trois lettres; par ex : 'Fri'"
        return WEEKDAYS[self.date.weekday()][0:3]

    def f(self):
        """
        Heure, au format 12h, et minutes (sans les minutes si elles valent zéro).
        Exemples : '1', '1:30', '2:05', '2'
        Extension propre à Django.
        """
        if self.date.minute == 0:
            return self.g()
        return '%s:%s' % (self.g(), self.i())

    def F(self):
        "Mois, textuel, version longue; par ex : 'Janvier'"
        return MONTHS[self.date.month]

    def g(self):
        "Heure, au format 12h, sans les zéros initiaux; de '1' à '12'"
        if self.date.hour == 0:
            return 12
        if self.date.hour > 12:
            return self.date.hour - 12
        return self.date.hour

    def G(self):
        "Heure, au format 24h, sans les zéros initiaux; de '0' à '23'"
        return self.date.hour

    def h(self):
        "Heure, au format 12h; de '01' à '12'"
        return '%02d' % self.g()

    def H(self):
        "Heure, au format 24h; de '00' à '23'"
        return '%02d' % self.G()

    def i(self):
        "Minutes; de '00' à '59'"
        return '%02d' % self.date.minute

    def I(self):
        "'1' si l'heure d'été est activée, '0' sinon."
        raise NotImplementedError

    def j(self):
        "Jour du mois sans les zéros initiaux; de '1' à '31'"
        return self.date.day

    def l(self):
        "Jour de la semaine, textuel, version longue; par ex : 'Vendredi'"
        return WEEKDAYS[self.date.weekday()]

    def L(self):
        "Booléen qui indique si l'année est une année bissextile; True ou False"
        return isleap(self.date.year)

    def m(self):
        "Mois; de '01' à '12'"
        return '%02d' % self.date.month

    def M(self):
        "Mois, en trois lettres; par ex : 'jan'"
        return MONTHS[self.date.month][0:3]

    def n(self):
        "Mois sans les zéros initiaux; de '1' à '12'"
        return self.date.month

    def N(self):
        "Les abréviations des mois au format Associated Press. Extension propre à Django."
        return MONTHS_AP[self.date.month]

    def O(self):
        "Différence d'heures avec l'heure de Greenwich (GMT), exprimée en heures; par ex : '+0200'"
        raise NotImplementedError

    def P(self):
        """
        Heure, au format 12h, minutes et 'a.m.'/'p.m.' (sans les minutes si elles valent zéro).
        Lorsqu'il est midi ou minuit, affiche 'midi' ou 'minuit'.
        Exemples : '1 a.m.', '1:30 p.m.', 'minuit', 'midi', '12:30 p.m.'
        Extension propre à Django.
        """
        if self.date.minute == 0 and self.date.hour == 0:
            return 'minuit'
        if self.date.minute == 0 and self.date.hour == 12:
            return 'midi'
        return '%s %s' % (self.f(), self.a())

    def r(self):
        "Format de date RFC 2822; par ex : 'Thu, 21 Dec 2000 16:01:07 +0200'"
        raise NotImplementedError

    def s(self):
        "Secondes; de '00' à '59'"
        return '%02d' % self.date.second

    def S(self):
        "Suffixe ordinal (en anglais) d'un nombre pour le jour du mois, sur deux lettres; 'st', 'nd', 'rd' ou 'th'"
        if self.date.day in (11, 12, 13): # Cas particuliers
            return 'th'
        last = self.date.day % 10
        if last == 1:
            return 'st'
        if last == 2:
            return 'nd'
        if last == 3:
            return 'rd'
        return 'th'

    def t(self):
        "Nombre de jours dans le mois; de '28' à '31'"
        raise NotImplementedError

    def T(self):
        "Fuseau horaire de la machine; par ex : 'EST' ou 'MDT'"
        raise NotImplementedError

    def U(self):
        "Secondes depuis l'époque Unix (1er Janvier 1970, 0h00 00s GMT)"
        raise NotImplementedError

    def w(self):
        "Jour de la semaine au format numérique, de '0' (Dimanche) à '6' (Samedi)"
        weekday = self.date.weekday()
        if weekday == 0:
            return 6
        return weekday - 1

    def W(self):
        "Numéro de semaine dans l'année ISO-8601, les semaines commencent le lundi"
        # L'algorithme provient de http://www.personal.ecu.edu/mccartyr/ISOwdALG.txt
        week_number = None
        jan1_weekday = self.date.replace(month=1, day=1).weekday() + 1
        weekday = self.date.weekday() + 1
        day_of_year = self.z()
        if day_of_year <= (8 - jan1_weekday) and jan1_weekday > 4:
            if jan1_weekday == 5 or (jan1_weekday == 6 and isleap(self.date.year-1)):
                week_number = 53
            else:
                week_number = 52
        else:
            if isleap(self.date.year):
                i = 366
            else:
                i = 365
            if (i - day_of_year) < (4 - weekday):
                week_number = 1
            else:
                j = day_of_year + (7 - weekday) + (jan1_weekday - 1)
                week_number = j / 7
                if jan1_weekday > 4:
                    week_number -= 1
        return week_number

    def Y(self):
        "Année sur 4 chiffres; par ex : '1999'"
        return self.date.year

    def y(self):
        "Année sur 2 chiffres; par ex : '99'"
        return str(self.date.year)[2:]

    def z(self):
        "Jour de l'année; de '0' à '365'"
        doy = self.year_days[self.date.month] + self.date.day
        if self.L() and self.date.month > 2:
            doy += 1
        return doy

    def Z(self):
        """Décalage horaire en secondes (de '-43200' à '43200'). Le décalage des
        zones à l'ouest de la zone UTC est négatif, et à l'est, il est positif."""
        raise NotImplementedError

    def format(self, formatstr):
        result = ''
        for char in formatstr:
            try:
                result += str(getattr(self, char)())
            except AttributeError:
                result += char
        return result

class TimeFormat:
    def __init__(self, t):
        self.time = t

    def a(self):
        "'a.m.' ou 'p.m.'"
        if self.time.hour > 11:
            return 'p.m.'
        else:
            return 'a.m.'

    def A(self):
        "'AM' ou 'PM'"
        return self.a().upper()

    def B(self):
        "Heure Internet Swatch"
        raise NotImplementedError

    def f(self):
        """
        Heure, au format 12h, et minutes (sans les minutes si elles valent zéro).
        Exemples : '1', '1:30', '2:05', '2'
        Extension propre à Django.
        """
        if self.time.minute == 0:
            return self.g()
        return '%s:%s' % (self.g(), self.i())

    def g(self):
        "Heure, au format 12h, sans les zéros initiaux; de '1' à '12'"
        if self.time.hour == 0:
            return 12
        if self.time.hour > 12:
            return self.time.hour - 12
        return self.time.hour

    def G(self):
        "Heure, au format 24h, sans les zéros initiaux; de '0' à '23'"
        return self.time.hour

    def h(self):
        "Heure, au format 12h; de '01' à '12'"
        return '%02d' % self.g()

    def H(self):
        "Heure, au format 24h; de '00' à '23'"
        return '%02d' % self.G()

    def i(self):
        "Minutes; de '00' à '59'"
        return '%02d' % self.time.minute

    def P(self):
        """
        Heure, au format 12h, minutes et 'a.m.'/'p.m.' (sans les minutes si elles valent zéro).
        Lorsqu'il est midi ou minuit, affiche 'midi' ou 'minuit'.
        Exemples : '1 a.m.', '1:30 p.m.', 'minuit', 'midi', '12:30 p.m.'
        Extension propre à Django.
        """
        if self.time.minute == 0 and self.time.hour == 0:
            return 'minuit'
        if self.time.minute == 0 and self.time.hour == 12:
            return 'midi'
        return '%s %s' % (self.f(), self.a())

    def s(self, s):
        "Secondes; de '00' à '59'"
        return '%02d' % self.time.second

    def format(self, formatstr):
        result = ''
        for char in formatstr:
            try:
                result += str(getattr(self, char)())
            except AttributeError:
                result += char
        return result

def format(value, format_string):
    "Fonction utile"
    df = DateFormat(value)
    return df.format(format_string)

def time_format(value, format_string):
    "Fonction utile"
    tf = TimeFormat(value)
    return tf.format(format_string)
